﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PdfRender
{
    public class OsShell
    {
        // 参数: fileName: 如 reboot
        //
        // arguments:
        //
        // output:
        //
        // millisecondsOfWait: 等待时间，默认10000。若不指定则永久等待
        //
        // WorkingDirectory: sets the working directory for the process to be started
        //
        // input:
        //
        // 返回结果: true if the associated process has exited; otherwise, false.
        public static bool Shell(string fileName, string arguments, out string output, int? millisecondsOfWait = 10000, string WorkingDirectory = null, string input = null)
        {
            output = null;
            Process process = new Process
            {
                StartInfo = new ProcessStartInfo(fileName, arguments)
                {
                    RedirectStandardOutput = true,
                    RedirectStandardInput = true,
                    UseShellExecute = false
                }
            };
            if (!string.IsNullOrEmpty(WorkingDirectory))
            {
                process.StartInfo.WorkingDirectory = WorkingDirectory;
            }

            EventHandler stopProcess = null;
            stopProcess = delegate
            {
                lock (stopProcess)
                {
                    AppDomain.CurrentDomain.ProcessExit -= stopProcess;
                    try
                    {
                        if (process != null)
                        {
                            if (!process.HasExited)
                            {
                                process.Kill();
                            }

                            process.Dispose();
                            process = null;
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
            };
            AppDomain.CurrentDomain.ProcessExit += stopProcess;
            try
            {
                process.Start();
                if (input != null)
                {
                    process.StandardInput.Write(input);
                }

                Task<string> task = process.StandardOutput.ReadToEndAsync();
                if (millisecondsOfWait.HasValue)
                {
                    task.Wait(millisecondsOfWait.Value);
                }
                else
                {
                    task.Wait();
                }

                if (task.IsCompleted)
                {
                    output = task.Result;
                    return true;
                }
            }
            finally
            {
                stopProcess(null, null);
            }

            return false;
        }

        // 参数: fileName: 如 reboot
        //
        // arguments:
        //
        // millisecondsOfWait: 等待时间，默认10000。为null则永久等待
        //
        // WorkingDirectory: sets the working directory for the process to be started
        //
        // input:
        //
        // 返回结果: true if the associated process has exited; otherwise, false.
        public static bool Shell(string fileName, string arguments, int? millisecondsOfWait = 10000, string WorkingDirectory = null, string input = null)
        {
            Process process = new Process
            {
                StartInfo = new ProcessStartInfo(fileName, arguments)
                {
                    UseShellExecute = false
                }
            };
            if (!string.IsNullOrEmpty(WorkingDirectory))
            {
                process.StartInfo.WorkingDirectory = WorkingDirectory;
            }

            EventHandler stopProcess = null;
            stopProcess = delegate
            {
                lock (stopProcess)
                {
                    AppDomain.CurrentDomain.ProcessExit -= stopProcess;
                    try
                    {
                        if (process != null)
                        {
                            if (!process.HasExited)
                            {
                                process.Kill();
                            }

                            process.Dispose();
                            process = null;
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
            };
            AppDomain.CurrentDomain.ProcessExit += stopProcess;
            try
            {
                process.Start();
                if (input != null)
                {
                    process.StandardInput.Write(input);
                }

                if (millisecondsOfWait.HasValue)
                {
                    return process.WaitForExit(millisecondsOfWait.Value);
                }

                process.WaitForExit();
                return true;
            }
            finally
            {
                stopProcess(null, null);
            }
        }
    }
}